﻿using Microsoft.Extensions.Caching.Memory;

namespace Utility
{
    /// <summary>
    /// 缓存帮助类
    /// </summary>
    public static class MemoryCacheHelper
    {

        // 创建缓存选项
        private static MemoryCacheEntryOptions cacheOptions = new MemoryCacheEntryOptions()
            .SetAbsoluteExpiration(TimeSpan.FromHours(24)) // 24小时后绝对过期
            .SetSlidingExpiration(TimeSpan.FromHours(1))    // 如果1小时内未被访问则过期
            .SetPriority(CacheItemPriority.High);            // 高优先级（内存不足时最后被移除）

        /// <summary>
        /// 声明缓存
        /// </summary>
        private static readonly MemoryCache _memoryCache = new MemoryCache(new MemoryCacheOptions());

        /// <summary>
        /// 获取缓存,如果缓存不存在会新建缓存。
        /// </summary>
        /// <typeparam name="T">模型</typeparam>
        /// <param name="key">缓存key</param>
        /// <param name="factory">缓存数据方法</param>
        /// <param name="expireTime">缓存过期时间（分钟）</param>
        /// <returns>返回缓存数据</returns>
        public static async Task<ReceiveStatus<T?>> GetCachedDataAsync<T>(string key, Func<Task<T>> factory, int expireTime)
        {
            ReceiveStatus<T?> receiveStatus = new ReceiveStatus<T?>();
            try
            {
                if (!_memoryCache.TryGetValue(key, out T? data))
                {
                    data = await factory.Invoke();
                    var options = new MemoryCacheEntryOptions()
                        .SetSlidingExpiration(TimeSpan.FromMinutes(expireTime));
                    _memoryCache.Set(key, data, options);
                }
                receiveStatus.data = data;
            }
            catch (Exception ex)
            {
                receiveStatus.success = false;
                receiveStatus.code = Enum.CodeStatuEnum.Error;
                receiveStatus.msg = ex.Message;
            }

            return receiveStatus;
        }

        /// <summary>
        /// 新建缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <param name="data">缓存数据</param>
        /// <param name="expireTime">缓存过期时间（分钟）</param>
        public static ReceiveStatus AddCache(string key, object data, int expireTime)
        {
            ReceiveStatus receiveStatus = new();
            try
            {
                var options = new MemoryCacheEntryOptions()
                .SetSlidingExpiration(TimeSpan.FromMinutes(expireTime));
                _memoryCache.Set(key, data, options);
            }
            catch (Exception ex)
            {
                receiveStatus.success = false;
                receiveStatus.code = Enum.CodeStatuEnum.Error;
                receiveStatus.msg = ex.Message;
            }
            return receiveStatus;
        }

        /// <summary>
        /// 获取缓存项
        /// </summary>
        /// <typeparam name="T">模型</typeparam>
        /// <param name="key">缓存key</param>
        /// <returns>返回缓存数据</returns>
        public static ReceiveStatus<T> GetCachedDataByKey<T>(string key)
        {
            ReceiveStatus<T> receiveStatus = new();
            try
            {
                if (_memoryCache.TryGetValue(key, out _))
                {
                    receiveStatus.data = _memoryCache.Get<T>(key);
                }
                else
                {
                    receiveStatus.success = false;
                    receiveStatus.code = Enum.CodeStatuEnum.Error;
                    receiveStatus.msg = string.Format("不存在缓存key：{0}", key);
                }
            }
            catch (Exception ex)
            {
                receiveStatus.success = false;
                receiveStatus.code = Enum.CodeStatuEnum.Error;
                receiveStatus.msg = ex.Message;
            }

            return receiveStatus;
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public static void Dispose()
        {
            _memoryCache.Dispose();
        }

        /// <summary>
        /// 根据缓存key，移除缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        public static void Remove(string key)
        {
            _memoryCache.Remove(key);
        }

        /// <summary>
        /// 清除所有缓存
        /// </summary>
        public static void ClearAllCache()
        {
            _memoryCache.Clear();
        }
    }
}
